package com.apikey.auth.interceptor;

import com.apikey.auth.config.ApiKeyProperties;
import com.apikey.auth.entity.AccessLog;
import com.apikey.auth.entity.ApiKey;
import com.apikey.auth.service.AccessLogService;
import com.apikey.auth.service.ApiKeyService;
import com.apikey.auth.validator.ApiKeyPermissionValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * API Key拦截器
 * 负责验证API Key的有效性和权限
 *
 * @author API Key Framework
 * @version 1.0
 */
public class ApiKeyInterceptor implements HandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(ApiKeyInterceptor.class);

    @Autowired
    private ApiKeyService apiKeyService;

    @Autowired
    private ApiKeyPermissionValidator permissionValidator;

    @Autowired
    private AccessLogService accessLogService;

    @Autowired
    private ApiKeyProperties properties;

    /**
     * 在请求处理之前进行拦截
     * 验证API Key的有效性和权限
     *
     * @param request  HTTP请求
     * @param response HTTP响应
     * @param handler  处理器
     * @return 是否继续处理请求
     * @throws Exception 异常
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        long startTime = System.currentTimeMillis();

        // 记录请求开始时间，用于后续计算响应时间
        request.setAttribute("startTime", startTime);

        // 检查是否需要跳过验证
        if (shouldSkipValidation(request)) {
            return true;
        }

        // 获取API Key
        String apiKey = extractApiKey(request);
        if (apiKey == null || apiKey.trim().isEmpty()) {
            logger.warn("API Key missing for request: {} {}", request.getMethod(), request.getRequestURI());
            sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "API Key is required");
            logAccess(request, response, null, startTime);
            return false;
        }

        try {
            // 验证API Key
            Optional<ApiKey> apiKeyOpt = apiKeyService.findByKeyValue(apiKey);
            if (!apiKeyOpt.isPresent()) {
                logger.warn("非法API Key: {}", apiKey);
                sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "非法的API Key");
                logAccess(request, response, apiKey, startTime);
                return false;
            }

            ApiKey apiKeyEntity = apiKeyOpt.get();

            // 验证API Key是否有效（未过期、未超限等）
            if (!apiKeyService.validateApiKey(apiKey)) {
                logger.warn("API Key无效: {}", apiKey);
                sendErrorResponse(response, HttpServletResponse.SC_FORBIDDEN, "API Key过期或失效");
                logAccess(request, response, apiKey, startTime);
                return false;
            }

            // 验证权限
            if (!permissionValidator.hasPathPermission(apiKey, request.getRequestURI(), request.getMethod())) {
                logger.warn("无权访问，API Key: {} to path: {}", apiKey, request.getRequestURI());
                sendErrorResponse(response, HttpServletResponse.SC_FORBIDDEN, "没有权限");
                logAccess(request, response, apiKey, startTime);
                return false;
            }

            // 增加使用次数
            apiKeyService.incrementUsage(apiKey);

            // 将API Key信息存储到请求属性中，供后续使用
            request.setAttribute("apiKey", apiKeyEntity);
            request.setAttribute("apiKeyValue", apiKey);

            logger.debug("API Key validation successful: {}", apiKey);
            return true;

        } catch (Exception e) {
            logger.error("Error validating API Key: " + apiKey, e);
            sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal server error");
            logAccess(request, response, apiKey, startTime);
            return false;
        }
    }

    /**
     * 请求处理完成后的处理
     * 记录访问日志
     *
     * @param request  HTTP请求
     * @param response HTTP响应
     * @param handler  处理器
     * @param ex       异常（如果有）
     * @throws Exception 异常
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                Object handler, Exception ex) throws Exception {
        Long startTime = (Long) request.getAttribute("startTime");
        String apiKey = (String) request.getAttribute("apiKeyValue");

        if (startTime != null) {
            logAccess(request, response, apiKey, startTime);
        }
    }

    /**
     * 检查是否应该跳过API Key验证
     *
     * @param request HTTP请求
     * @return 是否跳过验证
     */
    private boolean shouldSkipValidation(HttpServletRequest request) {
        String requestPath = request.getRequestURI();

        // 跳过管理页面
        if (requestPath.startsWith("/apikey-admin/") || requestPath.startsWith("/admin/") || requestPath.startsWith("/management/")) {
            return true;
        }

        // 跳过管理页面相关的API接口（不需要API Key验证）
        if (requestPath.startsWith("/api/apikeys") ||
                requestPath.startsWith("/api/history/stats") ||
                requestPath.startsWith("/api/history/recent") ||
                requestPath.startsWith("/api/access-logs") ||
                requestPath.startsWith("/api/system/stats") ||
                requestPath.startsWith("/api/applications")) {
            return true;
        }

        // 跳过所有管理员API路径
        if (requestPath.startsWith("/api/admin/")) {
            return true;
        }

        // 跳过静态资源
        if (requestPath.startsWith("/static/") || requestPath.startsWith("/css/") ||
                requestPath.startsWith("/js/") || requestPath.startsWith("/images/")) {
            return true;
        }

        // 跳过健康检查等
        if (requestPath.equals("/health") || requestPath.equals("/actuator/health")) {
            return true;
        }

        // 跳过H2控制台
        if (requestPath.startsWith("/h2-console/")) {
            return true;
        }

        // 检查配置的跳过路径
        if (properties.getInterceptor().getExcludePatterns() != null) {
            for (String skipPath : properties.getInterceptor().getExcludePatterns()) {
                if (requestPath.startsWith(skipPath)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 从请求中提取API Key
     * 支持多种方式：Header、Query Parameter
     *
     * @param request HTTP请求
     * @return API Key值
     */
    private String extractApiKey(HttpServletRequest request) {
        // 从Header中获取
        String apiKey = request.getHeader("X-API-Key");
        if (apiKey != null && !apiKey.trim().isEmpty()) {
            return apiKey.trim();
        }

        // 从Authorization Header中获取（Bearer token格式）
        String authorization = request.getHeader("Authorization");
        if (authorization != null && authorization.startsWith("Bearer ")) {
            return authorization.substring(7).trim();
        }

        // 从Query Parameter中获取
        apiKey = request.getParameter("api_key");
        if (apiKey != null && !apiKey.trim().isEmpty()) {
            return apiKey.trim();
        }

        // 从自定义Header名称中获取（如果配置了）
        if (properties.getInterceptor().getHeaderName() != null) {
            apiKey = request.getHeader(properties.getInterceptor().getHeaderName());
            if (apiKey != null && !apiKey.trim().isEmpty()) {
                return apiKey.trim();
            }
        }

        return null;
    }

    /**
     * 发送错误响应
     *
     * @param response HTTP响应
     * @param status   HTTP状态码
     * @param message  错误消息
     * @throws Exception 异常
     */
    private void sendErrorResponse(HttpServletResponse response, int status, String message) throws Exception {
        response.setStatus(status);
        response.setContentType("application/json;charset=UTF-8");

        String jsonResponse = String.format(
                "{\"error\": true, \"code\": %d, \"message\": \"%s\", \"timestamp\": \"%s\"}",
                status, message, LocalDateTime.now().toString()
        );

        response.getWriter().write(jsonResponse);
        response.getWriter().flush();
    }

    /**
     * 记录访问日志
     *
     * @param request   HTTP请求
     * @param response  HTTP响应
     * @param apiKey    API Key值
     * @param startTime 请求开始时间
     */
    private void logAccess(HttpServletRequest request, HttpServletResponse response,
                           String apiKey, long startTime) {
        try {
            // 检查必要的参数是否为空
            if (request == null || response == null || accessLogService == null) {
                logger.warn("Cannot log access: request, response or accessLogService is null");
                return;
            }

            // 检查是否应该跳过日志记录（管理页面相关请求）
            if (shouldSkipLogging(request)) {
                return;
            }

            long responseTime = System.currentTimeMillis() - startTime;

            // 收集请求头信息
            Map<String, String> requestHeaders = new HashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            if (headerNames != null) {
                while (headerNames.hasMoreElements()) {
                    String headerName = headerNames.nextElement();
                    if (headerName != null) {
                        // 不记录敏感信息
                        if (!headerName.toLowerCase().contains("authorization") &&
                                !headerName.toLowerCase().contains("api-key")) {
                            String headerValue = request.getHeader(headerName);
                            if (headerValue != null) {
                                requestHeaders.put(headerName, headerValue);
                            }
                        }
                    }
                }
            }

            // 收集请求参数
            Map<String, String> requestParams = new HashMap<>();
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (parameterMap != null) {
                parameterMap.forEach((key, values) -> {
                    if (key != null && values != null && values.length > 0 &&
                            !key.toLowerCase().contains("api_key")) {
                        requestParams.put(key, values[0]);
                    }
                });
            }

            // 收集响应头信息
            Map<String, String> responseHeaders = new HashMap<>();
            try {
                for (String headerName : response.getHeaderNames()) {
                    if (headerName != null) {
                        String headerValue = response.getHeader(headerName);
                        if (headerValue != null) {
                            responseHeaders.put(headerName, headerValue);
                        }
                    }
                }
            } catch (Exception e) {
                logger.debug("Failed to collect response headers", e);
            }

            // 创建访问日志对象
            AccessLog accessLog = new AccessLog();
            // 对于管理页面等不需要API Key的请求，apiKey可能为null，设置默认值
            accessLog.setApiKeyValue(apiKey != null ? apiKey : "ADMIN_REQUEST");

            // 安全获取请求URI
            String requestURI = null;
            try {
                requestURI = request.getRequestURI();
            } catch (Exception e) {
                logger.debug("Failed to get request URI", e);
            }
            accessLog.setRequestPath(requestURI);

            // 安全获取请求方法
            String method = null;
            try {
                method = request.getMethod();
            } catch (Exception e) {
                logger.debug("Failed to get request method", e);
            }
            accessLog.setRequestMethod(method);

            accessLog.setClientIp(getClientIpAddress(request));

            // 安全获取User-Agent
            String userAgent = null;
            try {
                userAgent = request.getHeader("User-Agent");
            } catch (Exception e) {
                logger.debug("Failed to get User-Agent", e);
            }
            accessLog.setUserAgent(userAgent);

            // 安全获取响应状态
            int responseStatus = 0;
            try {
                responseStatus = response.getStatus();
            } catch (Exception e) {
                logger.debug("Failed to get response status", e);
            }
            accessLog.setResponseStatus(responseStatus);

            accessLog.setResponseTime(responseTime);
            accessLog.setAccessTime(LocalDateTime.now());

            // 记录访问日志
            accessLogService.logAccess(accessLog);

        } catch (Exception e) {
            logger.error("Failed to log access", e);
        }
    }

    /**
     * 检查是否应该跳过日志记录
     *
     * @param request HTTP请求
     * @return 是否跳过日志记录
     */
    private boolean shouldSkipLogging(HttpServletRequest request) {
        String requestPath = request.getRequestURI();

        // 跳过管理页面
        if (requestPath.startsWith("/apikey-admin/") || requestPath.startsWith("/admin/") || requestPath.startsWith("/management/")) {
            return true;
        }

        // 跳过管理页面相关的API接口（不需要记录访问日志）
        if (requestPath.startsWith("/api/apikeys") ||
                requestPath.startsWith("/api/history/stats") ||
                requestPath.startsWith("/api/history/recent") ||
                requestPath.startsWith("/api/access-logs") ||
                requestPath.startsWith("/api/system/stats") ||
                requestPath.startsWith("/api/applications")) {
            return true;
        }

        // 跳过所有管理员API路径
        if (requestPath.startsWith("/api/admin/")) {
            return true;
        }

        // 跳过静态资源
        if (requestPath.startsWith("/static/") || requestPath.startsWith("/css/") ||
                requestPath.startsWith("/js/") || requestPath.startsWith("/images/")) {
            return true;
        }

        // 跳过健康检查等
        if (requestPath.equals("/health") || requestPath.equals("/actuator/health")) {
            return true;
        }

        // 跳过H2控制台
        if (requestPath.startsWith("/h2-console/")) {
            return true;
        }

        return false;
    }

    /**
     * 获取客户端IP地址
     *
     * @param request HTTP请求
     * @return 客户端IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        if (request == null) {
            return "unknown";
        }

        try {
            String xForwardedFor = request.getHeader("X-Forwarded-For");
            if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
                return xForwardedFor.split(",")[0].trim();
            }

            String xRealIp = request.getHeader("X-Real-IP");
            if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
                return xRealIp;
            }

            String remoteAddr = request.getRemoteAddr();
            return remoteAddr != null ? remoteAddr : "unknown";
        } catch (Exception e) {
            logger.debug("Failed to get client IP address", e);
            return "unknown";
        }
    }
}